package com.jinzhi.jzweb.strategy.decrypt.impl;


import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.jinzhi.common.base.CoreServiceImpl;
import com.jinzhi.common.utils.Result;
import com.jinzhi.common.utils.StringUtil;
import com.jinzhi.jzweb.dao.DecryptDao;
import com.jinzhi.jzweb.domain.DecryptDO;
import com.jinzhi.jzweb.pojo.*;
import com.jinzhi.jzweb.strategy.decrypt.DecryptService;
import com.jinzhi.jzweb.utils.CustomerDailyImportListener;
import com.jinzhi.jzweb.utils.CustomerDailyImportListener2;
import com.jinzhi.jzweb.utils.EasyPoiUtil;
import com.jinzhi.jzweb.utils.StringConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/*
 *  @author : JingChangTian
 *  @date   : 2024/3/18 20:20
 *  @description :  解密
 *
 */
@Service
public class DecryptServiceImpl extends CoreServiceImpl<DecryptDao, DecryptDO> implements DecryptService {


    @Override
    public Result importExcelDecryptNum1(MultipartFile file, String field) {
        List<DecryptDO> lottery = new ArrayList<>();
        if (!"application/vnd.ms-excel".equals(file.getContentType())) {
            return Result.fail("文件格式错误，请选择.xls文件");
        }

        if(lottery.isEmpty()){
            return Result.fail("Excel数据为空，请检查");
        }
        try{
            InputStream inputStream = file.getInputStream();
            lottery = EasyExcel.read(inputStream)
                    // 这个转换是成全局的， 所有java为string,excel为string的都会用这个转换器。
                    // 如果就想单个字段使用请使用@ExcelProperty 指定converter
                    .registerConverter(new StringConverter())
                    // 注册监听器，可以在这里校验字段
                    .registerReadListener(new CustomerDailyImportListener())
                    .head(DecryptNum1Dto.class)
                    .sheet()
                    .headRowNumber(2)
                    .doReadSync();
        } catch (Exception e) {
            e.getMessage();
            e.printStackTrace();
            return Result.fail(e.getMessage());
        }
        //根据赛场查询所有的一次加密
        List<DecryptDO> decryptDOS = this.selectList(new EntityWrapper<DecryptDO>().eq("field",field));
        if(decryptDOS.isEmpty()){
            return Result.ok(this.insertBatch(lottery));
        }
        //验证一次加密信息
        List<DecryptDO> finalLottery = lottery;
        lottery.forEach(a -> decryptDOS.forEach(b ->{
            if(Objects.equals(a.getNum1(),b.getNum1())){
                finalLottery.remove(a);
            }
        }));
        return Result.ok(this.insertBatch(finalLottery));
    }

    @Override
    public Result importExcelDecryptNum2(MultipartFile file, String field) {
        List<DecryptDO> lottery = new ArrayList<>();
        if (!"application/vnd.ms-excel".equals(file.getContentType())) {
            return Result.fail("文件格式错误，请选择.xls文件");
        }

        if(lottery.isEmpty()){
            return Result.fail("Excel数据为空，请检查");
        }
        try{
            InputStream inputStream = file.getInputStream();
            lottery = EasyExcel.read(inputStream)
                    // 这个转换是成全局的， 所有java为string,excel为string的都会用这个转换器。
                    // 如果就想单个字段使用请使用@ExcelProperty 指定converter
                    .registerConverter(new StringConverter())
                    // 注册监听器，可以在这里校验字段
                    .registerReadListener(new CustomerDailyImportListener2())
                    .head(DecryptNum2Dto.class)
                    .sheet()
                    .headRowNumber(2)
                    .doReadSync();
        } catch (Exception e) {
            e.getMessage();
            e.printStackTrace();
            return Result.fail(e.getMessage());
        }
        //根据赛场查询所有的一次加密
        List<DecryptDO> decryptDOS = this.selectList(new EntityWrapper<DecryptDO>().eq("field",field));
        if(decryptDOS.isEmpty()){
            return Result.fail("没有一次加密信息");
        }
        //验证一次加密信息
        List<DecryptDO> finalLottery = lottery;
        lottery.forEach(a -> decryptDOS.forEach(b ->{
            if(Objects.equals(a.getNum2(),b.getNum2())){
                finalLottery.remove(a);
            }
        }));
        //
        for (int i = 0; i < decryptDOS.size(); i++) {
            if(finalLottery.size()<i){
                break;
            }
            decryptDOS.get(i).setNum2(finalLottery.get(i).getNum2());
        }
        return Result.ok(this.updateBatchById(decryptDOS));
    }

    @Override
    public Result updateDecrypt(DecryptDO decryptDO) {
        //验证一二加密是否已经被其他组合绑定
        List<DecryptDO> doList =  this.selectList(new EntityWrapper<DecryptDO>()
                .eq("field",decryptDO.getField())
                .or("num1s",decryptDO.getNum1s())
                .or("num2s",decryptDO.getNum2s()));
        if(!doList.isEmpty()){
            return Result.fail("一二加密已经被其他组合绑定");
        }
        return Result.ok(this.updateById(decryptDO));
    }

    @Override
    public Result getDecrypt(DecryptDO decryptDO) {
        Page<DecryptDO> page = new Page<DecryptDO>(decryptDO.getCurrent(),decryptDO.getSize());
        //查询已经匹配的解密列表
        Page<DecryptDO> decryptDOPage = this.selectPage(page,new EntityWrapper<DecryptDO>()
                .eq(StringUtil.notEmpty(decryptDO.getField()),"field",decryptDO.getField())
                .eq(StringUtil.notEmpty(decryptDO.getNum1s()),"num1s",decryptDO.getNum1s())
                .eq(StringUtil.notEmpty(decryptDO.getNum2s()),"num2s",decryptDO.getNum2s())
        .isNotNull("num1s")
        .isNotNull("num2s"));
        return Result.ok(page);
    }

    @Override
    public Result getAddDecrypt(DecryptDO decryptDO) {
        //查询未匹配的解密列表
        List<DecryptDO> decryptDOs = this.selectList(new EntityWrapper<DecryptDO>()
                .eq(StringUtil.notEmpty(decryptDO.getField()),"field",decryptDO.getField())
                .eq(StringUtil.notEmpty(decryptDO.getNum1s()),"num1s",decryptDO.getNum1s())
                .eq(StringUtil.notEmpty(decryptDO.getNum2s()),"num2s",decryptDO.getNum2s())
                .isNull("num1s")
                .isNull("num2s"));
        return Result.ok(decryptDOs);
    }

    @Override
    public void downloadImportDecrypt(HttpServletResponse response, String field, Integer type) {
        List<DecryptNum1VO>  num1s = new ArrayList<>();
        List<DecryptNum2VO>  num2s = new ArrayList<>();
        List<DecryptNumVO>  num = new ArrayList<>();
        DecryptNum1VO decryptNum1VO = new DecryptNum1VO();
        DecryptNum2VO decryptNum2VO = new DecryptNum2VO();
        DecryptNumVO decryptNumVO = new DecryptNumVO();
        //根据赛场查询已匹配赛场信息
        List<DecryptDO> decryptDO = this.selectList(new EntityWrapper<DecryptDO>()
                .eq(StringUtil.notEmpty(field),"field",field)
                .isNotNull("num1s")
                .isNotNull("num2s"));
        decryptDO.forEach(a ->{
            //通过反射获取相同属性值
            try {
                copyProperties(a, decryptNum1VO);
                copyProperties(a, decryptNum2VO);
                copyProperties(a, decryptNumVO);
            } catch (Exception e) {
                e.printStackTrace();
            }
            num1s.add(decryptNum1VO);
            num2s.add(decryptNum2VO);
            num.add(decryptNumVO);
        });
        switch (type) {
            case 1:
                EasyPoiUtil.exportExcel(num1s, "一次解密导出", "一次解密导出", DecryptNum1VO.class, "一次解密导出", response);
            case 2:
                EasyPoiUtil.exportExcel(num2s, "二次解密导出", "二次解密导出", DecryptNum2VO.class, "二次解密导出", response);
            case 3:
                EasyPoiUtil.exportExcel(num, "解密导出", "解密导出", DecryptNumVO.class, "解密导出", response);
            default:
                return;
        }
    }






    /**
     * 反射赋值
     * @param source
     * @param target
     * @param <T>
     * @param <S>
     * @return
     * @throws Exception
     */
    public static <T, S> T copyProperties(S source, T target) throws Exception {
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        Field[] sourceFields = sourceClass.getDeclaredFields();
        for (Field sourceField : sourceFields) {
            String fieldName = sourceField.getName();
            Field targetField = null;
            try {
                targetField = targetClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                // 目标对象不存在该属性，忽略
                continue;
            }

            sourceField.setAccessible(true);
            targetField.setAccessible(true);

            Object value = sourceField.get(source);
            targetField.set(target, value);
        }
        return target;
    }

    @Override
    public Result deltedDecrypt(Long id) {
        DecryptDO decryptDO = this.selectById(id);
        if(decryptDO.getStatus()==1){
            return Result.fail("加密号已绑定考生，无法修改");
        }
        if(ObjectUtils.isEmpty(decryptDO)){
            return Result.fail("修改失败");
        }
        decryptDO.setNum1s(null);
        decryptDO.setNum2s(null);
        return Result.ok(this.updateById(decryptDO));
    }
}
